<template>
  <h3>表格框选变样式</h3>

  <h2>{{tableCols}}</h2>
  <tool-bar @changeRowCol="rowColChange" @mergeCell="handleCellMerge"/>

  <div id="wrap" ref="wrapRef">
    <table>
      <tr class="mt-tr" v-for="rowData in tableData">
        <td v-for="cellData in rowData"
            :ref="el => {tdNodes[cellData.id] = el}"
            :id="cellData.id"
            @mousedown="handleMouseDown"
            @mouseenter="handleMouseEnter"
            @mouseup="handleMouseUp"
            :class="getTdClass(cellData.id)">
          <my-cell :cellValue="cellData.value"/>
        </td>
      </tr>
    </table>
  </div>

</template>

<script setup>

import {defineComponent, onMounted, ref, reactive, computed, watch} from 'vue';
import MyCell from "@/components/MyCell";
import ToolBar from "@/components/ToolBar";

defineComponent({
  name: 'MyTable',
});
// 表格总行数
let tableRows = ref(20);
// 表格总列数
let tableCols = ref(12);
// 表格数据
const tableData = computed(() => {
  let data = [];
  let num = 0;
  for (let i = 0; i < tableRows.value; i++) {
    let row = [];
    for (let j = 0; j < tableCols.value; j++) {
      let cell = {};
      cell.id = i + '#' + j;
      cell.value = {
        num: num,
        text: '',
      };
      num++;
      row.push(cell);
    }
    data.push(row);
  }
  return data;
});

// 行数列数改变
const rowColChange = (type, num) => {
	if (type === 'row') {
    if (num === 1) {
    	tableRows.value++;
    }
    if (num === -1) {
			tableRows.value--;
    }
  }
	if (type === 'col') {
		if (num === 1) {
			tableCols.value++;
		}
		if (num === -1) {
			tableCols.value--;
		}
  }
};

// td dom节点
let tdNodes = ref({});
// 选中的td 的id值
let selectTds = ref([]);
// 边界上单元格td
let borderCellTds = reactive({
  topCells: [],
  bottomCells: [],
  leftCells: [],
  rightCells: []
});

// 单元格合并的信息
let mergeInfo = {
  tarId: '',        // 框选的矩形区域左上角第一个元素，给它设置colspan 和 rowspan
  rowIndex: 0,
  colIndex: 0,
  rowspan: 0,
  colspan: 0,
};

const wrapRef = ref(null);

// 初始化边界单元格
const initBorderCellTds = () => {
  borderCellTds.topCells = [];
  borderCellTds.bottomCells = [];
  borderCellTds.leftCells = [];
  borderCellTds.rightCells = [];
};

// 框选的单元格
let selectCell = reactive({
	firstindexrow: 0, // 合并起始行
	firstindexcol: 0, // 合并起始列
	curindexrow: 0, // 当前行
	curindexcol: 0  // 当前列
});

// 鼠标左键是否被按下
let isMouseDown = false;
let isSelectTds = ref(false);    // 是否选择了单元格

let time = '';

/**
 * 鼠标左键按下 记录初始第一个格子的坐标
 * @param event
 * @returns {boolean}
 */
const handleMouseDown = (event) => {
  event.preventDefault();
  if (event.button === 0) {   // 左键是否按下
    let currentTD = event.currentTarget;
    selectTds.value = [];
    initBorderCellTds();
		selectCell.firstindexrow = parseInt(currentTD.parentElement.rowIndex);
		selectCell.firstindexcol = parseInt(currentTD.cellIndex);
		selectCell.curindexrow = parseInt(currentTD.parentElement.rowIndex);
		selectCell.curindexcol = parseInt(currentTD.cellIndex);
    selectTds.value.push(currentTD.id);

    borderCellTds.topCells.push(currentTD.id);
    borderCellTds.bottomCells.push(currentTD.id);
    borderCellTds.leftCells.push(currentTD.id);
    borderCellTds.rightCells.push(currentTD.id);
    isMouseDown = true;

    time = setInterval(() => {
    	let rightCols = tableCols.value - selectCell.curindexcol;
			console.log(rightCols);
			if (rightCols <= 5) {
    		tableCols.value++;
				wrapRef.value.scrollLeft += 200;
      }
    }, 100);

    return false;
  }
};

/**
 *  鼠标按下的情况下 鼠标移动 计算鼠标画过的矩形区域 对这个区域内的格子进行修改样式
 * @param event
 */
const handleMouseEnter = (event) => {
  if (isMouseDown) {
    let currentTD = event.currentTarget;
    selectTds.value = [];
    initBorderCellTds();
    selectCell.curindexrow = currentTD.parentElement.rowIndex;
    selectCell.curindexcol = currentTD.cellIndex;
    // 计算矩形区域的四个顶角点的坐标
    let minrow = selectCell.curindexrow > selectCell.firstindexrow ? selectCell.firstindexrow : selectCell.curindexrow;
    let mincol = selectCell.curindexcol > selectCell.firstindexcol ? selectCell.firstindexcol : selectCell.curindexcol;
    let maxrow = selectCell.curindexrow > selectCell.firstindexrow ? selectCell.curindexrow : selectCell.firstindexrow;
    let maxcol = selectCell.curindexcol > selectCell.firstindexcol ? selectCell.curindexcol : selectCell.firstindexcol;
    // console.log(minrow, mincol, maxrow, maxcol);
    isSelectTds = true;

    mergeInfo.rowIndex = minrow;
    mergeInfo.colIndex = mincol;
    mergeInfo.rowspan = maxrow - minrow + 1;
    mergeInfo.colspan = maxcol - mincol + 1;
    mergeInfo.tarId = minrow + '#' + mincol;

    for (let i = minrow; i <= maxrow; i++) {
      for (let j = mincol; j <= maxcol; j++) {
        let coord = i + '#' + j;
        selectTds.value.push(coord);
        if (i === minrow) {
          borderCellTds.topCells.push(coord);
        }
        if (i === maxrow) {
          borderCellTds.bottomCells.push(coord);
        }
        if (j === mincol) {
          borderCellTds.leftCells.push(coord);
        }
        if (j === maxcol) {
          borderCellTds.rightCells.push(coord);
        }
      }
    }
  }
};

// 鼠标松开 清除定时器
const handleMouseUp = () => {
	clearInterval(time);
};

document.onmouseup = () => {
  isMouseDown = false;
};

/**
 * 计算 td 的类样式
 * @param id
 * @returns {{"bottom-cell-border": *, "right-cell-border": *, "td-IsSelect": *, "left-cell-border": *, "top-cell-border": *}}
 */
const getTdClass = (id) => {
  return {
    'td-IsSelect': selectTds.value.includes(id),
    'top-cell-border': borderCellTds.topCells.includes(id),
    'bottom-cell-border': borderCellTds.bottomCells.includes(id),
    'left-cell-border': borderCellTds.leftCells.includes(id),
    'right-cell-border': borderCellTds.rightCells.includes(id),
  }
};

/**
 * 处理合并单元格
 */
const handleCellMerge = () => {
  let tarTd = tdNodes.value[mergeInfo.tarId];
  let rowIndex = mergeInfo.rowIndex;
  let colIndex = mergeInfo.colIndex;
  let rowspan = mergeInfo.rowspan;
  let colspan = mergeInfo.colspan;

  if (rowIndex + rowspan > tableData.value.length || colIndex + colspan > tableData.value[0].length) {
    return;
  }
  tarTd.colSpan = colspan;
  tarTd.rowSpan = rowspan;

  for (let i = rowIndex; i < rowIndex + rowspan; i++) {
    for (let j = colIndex; j < colIndex + colspan; j++) {
      let tdId = i + '#' + j;
      if (tdId !== mergeInfo.tarId) {
        tdNodes.value[tdId].style.display = 'none';
      }
    }
  }
};





</script>

<style scoped>
#wrap {
  position: absolute;
  left: 200px;
  width: 1000px;
  height: 400px;
  overflow: auto;
  background-color: white;
  margin-top: 20px;
}

.btn {
  width: 100px;
  height: 40px;
}

table {
  border-collapse: collapse;
  border: 1px #C4C7CE solid;
}

th, td {
  padding: 0.2em 0.3em;
  width: 80px;
  height: 20px;
  box-sizing: border-box;
  border: 1px #C4C7CE solid;
  text-align: center;
  cursor: pointer;
}

td div {
  color: #2F4F4F;
  font-size: 14px;
  padding: 2px;
}

#operButton {
  position: absolute;
  left: 600px;
  top: 100px;
}

.td-IsSelect {
  background-color: #EAF2FF;
  border: 1px gray solid;
}

.top-cell-border {
  border-top: green 2px solid;
}

.bottom-cell-border {
  border-bottom: green 2px solid;
}

.left-cell-border {
  border-left: green 2px solid;
}

.right-cell-border {
  border-right: green 2px solid;
}


</style>
